#pragma once
#include <list>
#include "util.h"
#include <ptr_container/ptr_vector.hpp>

#include <vector>
#include "Exception.h"
/*///////////////////////////////////////////
same way to use as event
but we have more
We can add a listener to a specified catalog, and we can notify a specified catalog now.
Please refer to the KeyboardListener.h and KeyboardSource.h and KeyboardSource.cpp to find the usage.

*///////////////////////////////////////////
using namespace std;

namespace Core
{
	namespace Pattern
	{
		template <class ConMultiSource,class ConMultiListener,class Param=Core::Null>
		class IMultiListener;

		template <class ConSource,class Listener,size_t nEvent=1,class EventClass=Core::Null>
		class MultiSource;
		/*/Policy for Event class/*/
		template <class ConSource,class Event>
		class MultiEventPolicy
		{
		public:
			typedef Event EventType;
		protected:
			virtual EventType& getEvent()=0;
			~MultiEventPolicy(){};
		};

		template <class ConSource>
		class MultiEventPolicy<ConSource,Core::Null>
		{
		public:
			typedef ConSource EventType;
		protected:
			EventType& getEvent(){return *((ConSource*)this);}
			~MultiEventPolicy(){};
		};

		template <class ConMultiSource,class ConMultiListener,size_t nEvent,class EventClass>
		class MultiSource:public MultiEventPolicy<ConMultiSource,EventClass>
		{
			typedef ConMultiListener Listener;
			
		public:
			typedef MultiSource IMultiSource;
			class IMultiListener
			{
				friend class MultiSource;
			protected:
				typedef typename MultiSource::EventType SourceType;

				typedef void (ConMultiListener::*EventHandle)(SourceType&);
				vector<EventHandle> OnEvents;

				static const size_t numEvent=nEvent;
			public:
				void add(vector<EventHandle>& list)
				{
					OnEvents.assign(list.begin(),list.end());
					if(list.size()!=numEvent)
						throw (FailToInitIMultiListener());
				}


			};

		public:
			MultiSource()
				:m_nCatalog(nEvent)
			{
				for(size_t i=0;i<nEvent;i++)
				{
					m_listenerCatalog.push_back(new list<Listener* const>);
				}
			}

			//typedef EventClass EventType;
			void add(Listener*const listener, size_t catalog)
			{
				m_listenerCatalog[catalog].push_back (listener);
			}

			void remove(Listener*const listener, size_t catalog)
			{
				m_listenerCatalog[catalog].remove(listener);
			}

			static const size_t numEvent=nEvent;
		
			void notify(size_t catalog)
			{
				for(list<Listener*const> ::iterator i=m_listenerCatalog[catalog].begin();i!=m_listenerCatalog[catalog].end();i++)
				{
					Listener* const t=*i;
					if(!t) continue;
					(t->*(t->OnEvents[catalog]))(getEvent());
				}
			}
			void notify_all()
			{
				for(size_t i=0;i<m_listnerCatalog.size();i++)
				{
					notify(i);
				}
			}
			//virtual EventClass* getEvent();
		private:
			list<Listener*const > m_listenerList;

			size_t m_nCatalog;
			boost::ptr_vector< list<Listener*const > >m_listenerCatalog;
		};


		template <class ConMultiSource,class MultiListenerClass,size_t nEvent,class Param>
		inline bool operator==(const MultiSource<ConMultiSource,MultiListenerClass,nEvent,Param>& clock1,const MultiSource<ConMultiSource,MultiListenerClass,nEvent,Param>& clock2)
		{
			if(&clock1==&clock2)
				return true;
			else
				return false;
		}


		
	}
}